package timing.ukulele.android.bluetooth.view;

import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import timing.ukulele.android.R;
import timing.ukulele.android.bluetooth.util.StringUtils;

public class PullHeadView extends ViewGroup {
    private final static int UPDATING_IDLE = 0;
    private final static int UPDATING_READY = 1;
    private final static int UPDATING_ON_GOING = 2;
    private final static int UPDATING_FINISH = 3;
    private final static int MAX_PULL_HEIGHT_DP = 200;
    private final static int MAX_DURATION = 350;
    private final static int INVALID_STATE = -1;
    private final static String SP_NAME = "pull_list_update_time";
    private int mHeight;
    private int mDistance;
    private int mInitHeight;
    private boolean mImediateUpdate = false;
    private int mUpdateHeight;
    private boolean mCanUpdate;
    private int mNextState = INVALID_STATE;
    int mUpdatingStatus = UPDATING_IDLE;
    private int mMaxPullHeight;
    private Context mContext;
    private String mTimeTag;
    private ProgressBar pbRefreshing;
    private ImageView ivArrow;
    private TextView tvRefreshText;
    private TextView tvRefreshTime;
    private RotateAnimation mFlipAnimation;
    private RotateAnimation mReverseFlipAnimation;
    private String strRefreshing;
    private String strPullRefresh;
    private String strReleaseRefresh;
    private CloseTimer mUpdateTimer;
    private CloseTimer mResettimer;
    private OnStateListerer mListener;
    private static final Interpolator sInterpolator = new Interpolator() {

        public float getInterpolation(float t) {
            t -= 1.0f;
            return t * t * t + 1.0f;
        }

    };

    public PullHeadView(Context context) {
        super(context);
        initView(context);
    }

    public PullHeadView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public PullHeadView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context) {
        this.mContext = context;

        mMaxPullHeight = (int) (context.getResources().getDisplayMetrics().density * MAX_PULL_HEIGHT_DP + 0.5f);
        LayoutInflater.from(context).inflate(R.layout.view_layout_list_head, this, true);
        pbRefreshing = findViewById(R.id.pb_refresh);
        ivArrow = findViewById(R.id.imageview_refresh);
        tvRefreshText = findViewById(R.id.tv_pull_to_refresh_text);
        tvRefreshTime = findViewById(R.id.tv_pull_to_refresh_time);
        strPullRefresh = mContext.getString(R.string.pull_to_refresh_pull_label);
        strReleaseRefresh = mContext.getString(R.string.release_to_refresh_pull_label);
        strRefreshing = mContext.getString(R.string.string_refreshing);

        applyPullHeadViewTheme();
        /**
         * 初始化动画
         */
        mFlipAnimation = new RotateAnimation(0, -180,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        mFlipAnimation.setInterpolator(new LinearInterpolator());
        mFlipAnimation.setDuration(200);
        mFlipAnimation.setFillAfter(true);

        /**
         * 反转动画
         */
        mReverseFlipAnimation = new RotateAnimation(-180, 0,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
        mReverseFlipAnimation.setDuration(200);
        mReverseFlipAnimation.setFillAfter(true);
    }

    public void showInitState() {
        ivArrow.setVisibility(View.VISIBLE);
        pbRefreshing.setVisibility(View.GONE);
        tvRefreshText.setText(strPullRefresh);
    }

    public void showInitTime() {
        String lastTime = getLastTimeLable();
        /* SLog.v(TAG, "lastTime:"+lastTime); */
        if (lastTime != null) {
            tvRefreshTime.setVisibility(View.VISIBLE);
            tvRefreshTime.setText(lastTime);
        } else {
            tvRefreshTime.setVisibility(View.GONE);
        }
    }

    public void showRefreshingState() {
        ivArrow.clearAnimation();
        ivArrow.setVisibility(View.GONE);
        pbRefreshing.setVisibility(View.VISIBLE);
        tvRefreshText.setText(strRefreshing);
    }

    /**
     * 只有它在从release to refresh是才需要显示动画
     */
    public void showPullState() {
        ivArrow.setVisibility(View.VISIBLE);
        pbRefreshing.setVisibility(View.GONE);
        tvRefreshText.setText(strPullRefresh);
        ivArrow.clearAnimation();
        ivArrow.startAnimation(mReverseFlipAnimation);
    }

    public void showReleaseState() {
        ivArrow.setVisibility(View.VISIBLE);
        pbRefreshing.setVisibility(View.GONE);
        tvRefreshText.setText(strReleaseRefresh);
        ivArrow.clearAnimation();
        ivArrow.startAnimation(mFlipAnimation);
    }

    public void setStateListener(OnStateListerer listener) {
        mListener = listener;
    }

    public void setTimeTag(String timeTag) {
        this.mTimeTag = timeTag;
    }

    /**
     * 初始化上次更新时间
     */
    private String getLastTimeLable() {
        if (mTimeTag != null) {
            long time = mContext.getSharedPreferences(SP_NAME, 0).getLong(mTimeTag, 0);
            String format = mContext.getString(R.string.string_update_time,
                    StringUtils.getTimeDisplayNameNormal(time));
            return format;
        } else {
            return "最后更新于：刚刚";
        }
    }

    /**
     * 刷新成功后调用
     */
    public void updateLastTimeLable() {
        if (mTimeTag != null && mTimeTag.length() > 0) {
            long curTime = System.currentTimeMillis();
            mContext.getSharedPreferences(SP_NAME, 0).edit()
                    .putLong(mTimeTag, curTime).commit();
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final View childView = getChildView();
        if (childView == null) {
            return;
        }
        final int childViewWidth = childView.getMeasuredWidth();
        final int childViewHeight = childView.getMeasuredHeight();
        final int measuredHeight = getMeasuredHeight();
        childView.layout(0, measuredHeight - childViewHeight, childViewWidth,
                measuredHeight);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (mHeight < 0) {
            mHeight = 0;
        }
        setMeasuredDimension(width, mHeight);
        final View childView = getChildView();
        if (childView != null) {
            childView.measure(widthMeasureSpec, heightMeasureSpec);
            mUpdateHeight = childView.getMeasuredHeight();
            /* SLog.v(TAG, "mUpdateHeight"+mUpdateHeight); */
        }
    }

    public void startUpdate() {
        mUpdatingStatus = UPDATING_READY;
        mInitHeight = mHeight;
        mDistance = mInitHeight - mUpdateHeight;
        if (mDistance < 0) {
            mDistance = mInitHeight;
        }
        int duration = (int) (mDistance * 3);
        duration = duration > MAX_DURATION ? MAX_DURATION : duration;
        /* Log.d(VIEW_LOG_TAG, "duration:" + duration); */
        mUpdateTimer = new CloseTimer(duration);
        mUpdateTimer.startTimer();
    }

    public void reset(int nextState) {
        if (mUpdatingStatus == UPDATING_ON_GOING) {
            mUpdatingStatus = UPDATING_FINISH;
        }
        mDistance = mInitHeight = mHeight;
        int duration = (int) (mDistance * 4);
        duration = duration > MAX_DURATION ? MAX_DURATION : duration;
        mNextState = nextState;
        if (mUpdateTimer != null) {
            mUpdateTimer.cancel();
        }
        mResettimer = new CloseTimer(duration);
        mResettimer.startTimer();
    }

    public boolean isUpdateNeeded() {
        if (mImediateUpdate) {
            mImediateUpdate = false;
            return true;
        }

        final int distance = mHeight - mUpdateHeight;
        boolean needUpdate = distance >= 0;
        return needUpdate;
    }

    public void moveToUpdateHeight() {
        showInitTime();
        setHeaderHeight(mUpdateHeight);
        mImediateUpdate = true;
    }

    private class CloseTimer extends CountDownTimer {
        private long mStart;
        private float mDurationReciprocal;
        private static final int COUNT_DOWN_INTERVAL = 15;

        public CloseTimer(long millisInFuture) {
            super(millisInFuture, COUNT_DOWN_INTERVAL);
            mDurationReciprocal = 1.0f / millisInFuture;
        }

        public void startTimer() {
            mStart = AnimationUtils.currentAnimationTimeMillis();
            start();
        }

        @Override
        public void onFinish() {
            if (mNextState != INVALID_STATE) {
                mNextState = INVALID_STATE;
                if (mListener != null) {
                    mListener.onReset();
                }
            }
            setHeaderHeight((int) (mInitHeight - mDistance));
        }

        @Override
        public void onTick(long millisUntilFinished) {
            final int interval = (int) (AnimationUtils
                    .currentAnimationTimeMillis() - mStart);
            float x = interval * mDurationReciprocal;
            x = sInterpolator.getInterpolation(x);
            setHeaderHeight((int) (mInitHeight - mDistance * x));
        }

    }

    private View getChildView() {
        final int childCount = getChildCount();
        if (childCount != 1) {
            return null;
        }
        return getChildAt(0);
    }

    public void setHeaderHeight(int height) {
        /* SLog.v(TAG, "mHeight:"+mHeight+"height:"+height); */
        if (mHeight == height && height == 0) {
            showInitTime();
            return;
        }
        if (height > mMaxPullHeight) {
            return;
        }
        mHeight = height;
        if (mUpdatingStatus != UPDATING_IDLE) {
            if (mUpdatingStatus == UPDATING_READY) {
                showRefreshingState();
                mUpdatingStatus = UPDATING_ON_GOING;
            }
        } else {
            if ((height < mUpdateHeight) && mCanUpdate) {
                showPullState();
                mCanUpdate = false;
            } else if ((height >= mUpdateHeight) && !mCanUpdate) {
                showReleaseState();
                mCanUpdate = true;
            }
        }
        requestLayout();
        if (height == 0) {
            mUpdatingStatus = UPDATING_IDLE;
            mCanUpdate = false;
            showInitState();
        }
    }

    public void applyPullHeadViewTheme() {
        ivArrow.setImageResource(R.drawable.refresh_arrow);
        tvRefreshText.setTextColor(mContext.getResources().getColor(R.color.pull_to_refresh_tips_color));
        tvRefreshTime.setTextColor(mContext.getResources().getColor(R.color.pull_to_refresh_time_color));
    }

    /**
     * 状态重置
     */
    public interface OnStateListerer {
        public void onReset();
    }
}